package com.it.gmall.cart.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.it.gmall.cart.mapper.CartMapper;
import com.it.gmall.common.constant.RedisConst;
import com.it.gmall.common.util.AuthContextHolder;
import com.it.gmall.model.cart.CartInfo;
import com.it.gmall.model.product.SkuInfo;
import com.it.gmall.product.client.ProductFeignClient;
import jdk.nashorn.internal.ir.CallNode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class CartApiServiceImpl extends ServiceImpl<CartMapper,CartInfo> implements CartApiService {

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private ProductFeignClient productFeignClient;
    @Autowired
    private CartServiceAsync cartServiceAsync;
    @Autowired
    private CartMapper cartMapper;

    // 点击加入购物车-查
    @Override
    public CartInfo toCart(Long skuId) {
//        String userId = "3";
        ServletRequestAttributes requestAttributes =
                (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        String userId = AuthContextHolder.getUserId(request);
        if(StringUtils.isEmpty(userId)){
            userId = AuthContextHolder.getUserTempId(request);
        }

        String cacheKey = RedisConst.USER_KEY_PREFIX+userId+RedisConst.USER_CART_KEY_SUFFIX;
        CartInfo cartInfo = (CartInfo) redisTemplate.opsForHash().get(cacheKey, skuId.toString());
        return cartInfo;
    }

    // 点击加入购物车-加
    @Override
    public void addCart(Long skuId, Integer skuNum,String userId) {
        /*第一部分 写redis*/
        // 0.写死一个id
//        String userId = "3";

        // 1.查询redis是否有这条数据
        CartInfo cartInfo =
                (CartInfo) redisTemplate.opsForHash().get(RedisConst.USER_KEY_PREFIX+userId+RedisConst.USER_CART_KEY_SUFFIX,skuId.toString() );
        if(null!=cartInfo){// redis中有这个数据 更新数量即可
            cartInfo.setSkuNum(cartInfo.getSkuNum()+skuNum);
            // 如果redis中有 代表数据库中也有 异步修改数据库中的信息
            cartServiceAsync.updateCartInfoToDB(cartInfo);
        }else{// redis中没有这个数据 新增一条数据
            // 根据商品id查询商品的信息
            SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
            if(null!=skuInfo){
                // 将商品的信息放到购物车信息中
                cartInfo = new CartInfo();
                cartInfo.setUserId(userId);
                cartInfo.setSkuId(skuInfo.getId());
                cartInfo.setCartPrice(productFeignClient.getSkuPrice(skuId)); // 商品实时价格
                cartInfo.setSkuNum(skuNum);
                cartInfo.setImgUrl(skuInfo.getSkuDefaultImg());
                cartInfo.setSkuName(skuInfo.getSkuName());
            }
            // 往数据中添加这个商品信息 异步添加数据库
            cartServiceAsync.addCartInfoToDB(cartInfo);
        }
        // 不管原来redis中是否有这条数据 都将他的复选框状态设置为选中
        cartInfo.setIsChecked(1);
        // 将数据放到redis中
        redisTemplate.opsForHash().put(RedisConst.USER_KEY_PREFIX+userId+RedisConst.USER_CART_KEY_SUFFIX,skuId.toString(),cartInfo);

        // 返回数据
        // return cartInfo;
    }

    /*点击去购物车结算
    * 1、获取用户的id 临时和真实的
    * 2、如果真实id为空 临时id也没空 则购物车为空
    * 3、如果真实id为空 临时id有值 则购物车为临时用户的购物车
    * 4、如果真实id有值 临时id没值 则购物车为真实用的购物车
    * 5、如果真实id和临时id都有值 合并真实和临时用户的购物车 删除临时用户的购物车
    * */
    @Override
    public List<CartInfo> goToCart(String userId, String userTempId) {
        // 1.获取用户id和临时id
        System.out.println("userId = " + userId);
        System.out.println("userTempId = " + userTempId);
        // 2.判断
        if(!StringUtils.isEmpty(userId)){ // 如果用户id不为空
            if(!StringUtils.isEmpty(userTempId)){ // 真实和临时的都不为空 合并 删除临时
                return getMergeCart(userId, userTempId);
            }else{ // 临时用户id为空
                return this.getUserCart(userId);
            }
        }else{ // 用户id为空
            if(!StringUtils.isEmpty(userTempId)){ // 临时用户id不为空
                return this.getUserCart(userTempId);
            }else{ // 临时用户id和用户id都为空
                return null;
            }

        }
    }

    // 获取真实和临时用户购物车大合并
    private List<CartInfo> getMergeCart(String userId, String userTempId) {
        String cacheKey = RedisConst.USER_KEY_PREFIX+userId+RedisConst.USER_CART_KEY_SUFFIX;
        String cacheKeyTempId = RedisConst.USER_KEY_PREFIX+userTempId+RedisConst.USER_CART_KEY_SUFFIX;

        List<CartInfo> userCartByUserId = this.getUserCart(userId);
        List<CartInfo> userCartByUserTempId = this.getUserCart(userTempId);

        if(!CollectionUtils.isEmpty(userCartByUserId)){
            if (!CollectionUtils.isEmpty(userCartByUserTempId)){
                // 将用户的购物车集合转换为map对象
                Map<String, CartInfo> mapByUserId = userCartByUserId.stream().collect(Collectors.toMap(
                        cartInfo -> cartInfo.getSkuId().toString(), cartInfo -> cartInfo));

                // 遍历临时的用户id对应的购物车
                for (CartInfo c : userCartByUserTempId) {
                    CartInfo cartInfo = mapByUserId.get(c.getSkuId().toString());
                    if(null!=cartInfo){ // 用户的真实购物车中有这条数据 修改数量
                        cartInfo.setSkuNum(cartInfo.getSkuNum()+c.getSkuNum());
                        cartInfo.setIsChecked(1);
                    }else{ // 用户的真实购物车没有这条数据 插入这条数据
                        c.setIsChecked(1);
                        c.setUserId(userId);
                        mapByUserId.put(c.getSkuId().toString(),c);
                    }
                }

                // 统一修改缓存
                // 1.1 将原有临时用户id对应的数据删除
                redisTemplate.delete(cacheKeyTempId);
                // 1.2 修改真实用户id的数据
                redisTemplate.opsForHash().putAll(cacheKey,mapByUserId);

                // 统一修改DB
                // 1.1 将原来的真实用户id和临时用户id对应的数据都删除
                cartMapper.delete(new QueryWrapper<CartInfo>()
                        .in("user_id",userId,userTempId));
                // 1.2 将新的数据批量添加
                List<CartInfo> cartInfos = new ArrayList<>(mapByUserId.values());
                this.saveBatch(cartInfos);

                return cartInfos;
            }else{
                //临时用户的购物车集合是没有
                return userCartByUserId;
            }
        }else{
            //真实用户的购物车集合 没有 直接返回临时用户的购物车集合
            return userCartByUserTempId;
        }
    }

    // 根据用户的id从缓存中获取用户的购物车数据
    private List<CartInfo> getUserCart(String userId) {
        String cacheKey = RedisConst.USER_KEY_PREFIX+userId+RedisConst.USER_CART_KEY_SUFFIX;
        // 从缓存中获取数据
        List<CartInfo> cartInfoList = redisTemplate.opsForHash().values(cacheKey);

        // 更新实时价格并返回数据
        /*cartInfoList.stream().forEach(cartInfo -> {
            cartInfo.setSkuPrice(productFeignClient.getSkuPrice(cartInfo.getSkuId()));
        });*/

        // 更新实时价格并且按照价格排序并且返回数据
        /*前边减后边 升序
        * 后边减前边 降序*/
        return cartInfoList.stream().peek(cartInfo -> {
            cartInfo.setSkuPrice(productFeignClient.getSkuPrice(cartInfo.getSkuId()));
        }).sorted((c1,c2)->{
            return c2.getSkuPrice().intValue() - c1.getSkuPrice().intValue();
        }).collect(Collectors.toList());
    }

    // 点击取消选中和选中商品
    @Override
    public void checkCart(String skuId, Integer isChecked) {
        // 获取用户id
        ServletRequestAttributes servletRequestAttributes =
                (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        String userId = AuthContextHolder.getUserId(request);
        if(StringUtils.isEmpty(userId)){
            //临时用户ID  万一之前加入购物车  有了真实用户ID之后 之前临时用户ID加的那些商品还在吗
            userId = AuthContextHolder.getUserTempId(request);
        }

        // 缓存中的名称
        String cacheKey = RedisConst.USER_KEY_PREFIX+userId+RedisConst.USER_CART_KEY_SUFFIX;

        // 根据用户id和商品id修改查询商品
        CartInfo cartInfo = (CartInfo) redisTemplate.opsForHash().get(cacheKey, skuId);

        // 并修改商品的选中状态
        cartInfo.setIsChecked(isChecked);

        // 修改redis的数据
        redisTemplate.opsForHash().put(cacheKey,skuId.toString(),cartInfo);
        // 修改持久层mysql的数据
        cartServiceAsync.updateCartInfoToDB(cartInfo);
    }

    // 获取选中商品并返回
    @Override
    public List<CartInfo> getCheckedCartInfo(String userId) {
        // 缓存中的名称
        String cacheKey = RedisConst.USER_KEY_PREFIX+userId+RedisConst.USER_CART_KEY_SUFFIX;
        // 获取用户所有的购物车商品
        List<CartInfo> cartInfoList = redisTemplate.opsForHash().values(cacheKey);
        List<CartInfo> collect = cartInfoList.stream().filter(cartInfo -> 1 == cartInfo.getIsChecked())
                .peek(cartInfo -> {
                // 查询商品的实时价格
                cartInfo.setSkuPrice(productFeignClient.getSkuPrice(cartInfo.getSkuId()));
            }).collect(Collectors.toList());
        return collect;
    }
}
